package cn.sciento.transfer.infra.datasource.provider;

import cn.sciento.core.convertor.ApplicationContextHelper;
import cn.sciento.core.exception.CommonException;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.sql.DataSource;
import org.apache.commons.lang3.StringUtils;
import cn.sciento.boot.platform.ds.DatasourceHelper;
import cn.sciento.boot.platform.ds.vo.DatasourceVO;
import cn.sciento.core.base.BaseConstants;
import cn.sciento.transfer.infra.datasource.DynamicRoutingDataSource;
import cn.sciento.transfer.infra.datasource.factory.DataSourceFactory;
import cn.sciento.transfer.infra.datasource.properties.BasicDataSourceProperties;
import cn.sciento.transfer.infra.datasource.properties.DataSourcePoolType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class TransferDataSourceProvider implements AbstractDataSourceProvider {
  private static Logger LOGGER = LoggerFactory.getLogger(TransferDataSourceProvider.class);
  
  private static final String NO_DATASOURCE_POOL_TYPE = "No";
  
  private static final String DATASOURCE_PURPOSE_DT = "DT";
  
  private static final String DATASOURCE_CACHE_KEY_PREFIX = "hpfm:datasource";
  
  private static Map<String, DataSource> dataSourceMap = new ConcurrentHashMap<>();
  
  private static Set<String> dataSourceServiceSet = new HashSet<>();
  
  public Map<String, DataSource> loadDataSources() {
    return dataSourceMap;
  }
  
  public static String getDataSourceKey(String dataSourceCode) {
    return "DT:" + dataSourceCode;
  }
  
  public static void loadDataSource(String dataSourceCode, String serviceName) {
    if (dataSourceMap.get(getDataSourceKey(dataSourceCode)) != null && dataSourceServiceSet
      .contains(generateUniqueValueFromDatasourceAndService(dataSourceCode, serviceName)))
      return; 
    DatasourceHelper datasourceHelper = ApplicationContextHelper.getContext().getBean(DatasourceHelper.class);
    if (datasourceHelper == null)
      throw new CommonException(String.format("can not find datasourceHelper"));
    DatasourceVO datasourceDTO = datasourceHelper.getDatasource("DT", dataSourceCode, serviceName);
    if (datasourceDTO == null)
      throw new CommonException(String.format("Current datasource %s doesn't assign service %s.", dataSourceCode, serviceName));
    if (dataSourceMap.get(getDataSourceKey(dataSourceCode)) == null) {
      BasicDataSourceProperties basicDataSourceProperties = new BasicDataSourceProperties();
      String dbPoolType = DataSourcePoolType.DEFAULT.type();
      if (!StringUtils.isEmpty(datasourceDTO.getDbPoolType()) && !"No".equals(datasourceDTO.getDbPoolType()))
        dbPoolType = datasourceDTO.getDbPoolType(); 
      basicDataSourceProperties.setDataSourcePoolType(DataSourcePoolType.valueOf(dbPoolType.toUpperCase()))
        .setDriverClassName(datasourceDTO.getDriverClass())
        .setUrl(datasourceDTO.getDatasourceUrl())
        .setUsername(datasourceDTO.getUsername())
        .setPassword(datasourceDTO.getPasswordEncrypted())
        .setOptions(datasourceDTO.getOptions());
      DataSource dataSource = DataSourceFactory.createDataSource(basicDataSourceProperties);
      dataSourceMap.putIfAbsent(getDataSourceKey(dataSourceCode), dataSource);
      DynamicRoutingDataSource.runtimeLoadDataSource(getDataSourceKey(dataSourceCode), dataSource);
    } 
    dataSourceServiceSet.add(generateUniqueValueFromDatasourceAndService(dataSourceCode, serviceName));
  }
  
  private static String generateRedisKey(String dataSourceCode, String serviceName) {
    long organizationId = BaseConstants.DEFAULT_TENANT_ID;
    String dsPurposeCode = "DT";
    return StringUtils.join("hpfm:datasource", ":", dsPurposeCode, ":",
            organizationId, ":", dataSourceCode, ":", serviceName);
  }
  
  private static String generateUniqueValueFromDatasourceAndService(String dataSourceCode, String serviceName) {
    return dataSourceCode + ":" + serviceName;
  }
}
